﻿using System;
using System.Collections.Generic;
using System.Linq;
using Castle.DynamicProxy;

namespace Wisdom.Core
{
    /// <summary>
    /// 描述：对象容器基类
    /// </summary>
    public abstract class ObjectContainer : Disposable, IObjectContainer
    {
        #region Private Fields
        private readonly IInterceptorSelector interceptorSelector = new InterceptorSelector();
        private readonly ProxyGenerator proxyGenerator = new ProxyGenerator();
        private readonly ProxyGenerationOptions proxyGenerationOptions;
        #endregion

        #region Ctor
        /// <summary>
        /// Initializes a new instance of <c>ObjectContainer</c> class.
        /// </summary>
        protected ObjectContainer()
        {
            this.proxyGenerationOptions = new ProxyGenerationOptions { Selector = interceptorSelector };
        }
        #endregion

        #region Private Methods
        private object GetProxyObject(Type targetType, object targetObject)
        {
            IInterceptor[] interceptors = AppRuntime.Instance.CurrentApplication.Interceptors.ToArray();

            if (interceptors.Length == 0)
                return targetObject;

            if (targetType.IsInterface)
            {
                object obj;
                var proxyGenerationOptionsForInterface = new ProxyGenerationOptions { Selector = interceptorSelector };
                Type targetObjectType = targetObject.GetType();
                if (targetObjectType.IsDefined(typeof(BaseTypeForInterfaceProxyAttribute), false))
                {
                    var baseTypeForIPAttribute = targetObjectType.GetCustomAttributes(typeof(BaseTypeForInterfaceProxyAttribute), false)[0] as BaseTypeForInterfaceProxyAttribute;
                    proxyGenerationOptionsForInterface.BaseTypeForInterfaceProxy = baseTypeForIPAttribute.BaseType;
                }
                if (targetObjectType.IsDefined(typeof(AdditionalInterfaceToProxyAttribute), false))
                {
                    List<Type> intfTypes = targetObjectType.GetCustomAttributes(typeof(AdditionalInterfaceToProxyAttribute), false)
                                                           .Select(p =>
                                                           {
                                                               var attrib = p as AdditionalInterfaceToProxyAttribute;
                                                               return attrib.InterfaceType;
                                                           }).ToList();
                    obj = proxyGenerator.CreateInterfaceProxyWithTarget(targetType, intfTypes.ToArray(), targetObject, proxyGenerationOptionsForInterface, interceptors);
                }
                else
                    obj = proxyGenerator.CreateInterfaceProxyWithTarget(targetType, targetObject, proxyGenerationOptionsForInterface, interceptors);
                return obj;
            }
            return proxyGenerator.CreateClassProxyWithTarget(targetType, targetObject, proxyGenerationOptions, interceptors);
        }
        #endregion

        #region Protected Methods
        /// <summary>
        /// Gets the service object of the specified type.
        /// </summary>
        /// <typeparam name="T">The type of the service object.</typeparam>
        /// <returns>The instance of the service object.</returns>
        protected virtual T DoGetService<T>()
        {
            return (T)this.DoGetService(typeof(T));
        }
        /// <summary>
        /// Gets the service object of the specified type, with overrided
        /// arguments provided.
        /// </summary>
        /// <typeparam name="T">The type of the service object.</typeparam>
        /// <param name="overridedArguments">The overrided arguments to be used when getting the service.</param>
        /// <returns>The instance of the service object.</returns>
        protected virtual T DoGetService<T>(object overridedArguments)
        {
            return (T)this.DoGetService(typeof(T), overridedArguments);
        }
        /// <summary>
        /// Gets the service object of the specified type.
        /// </summary>
        /// <param name="serviceType">An object that specifies the type of service object to get.</param>
        /// <returns>A service object of type serviceType.-or- null if there is no service object
        /// of type serviceType.</returns>
        protected abstract object DoGetService(Type serviceType);
        /// <summary>
        /// Gets the service object of the specified type, with overrided
        /// arguments provided.
        /// </summary>
        /// <param name="serviceType">The type of the service to get.</param>
        /// <param name="overridedArguments">The overrided arguments to be used when getting the service.</param>
        /// <returns>The instance of the service object.</returns>
        protected abstract object DoGetService(Type serviceType, object overridedArguments);
        /// <summary>
        /// Resolves all the objects from the specified type.
        /// </summary>
        /// <param name="serviceType">The type of the objects to be resolved.</param>
        /// <returns>A <see cref="System.Array"/> object which contains all the objects resolved.</returns>
        protected abstract Array DoGetServices(Type serviceType);
        /// <summary>
        /// Resolves all the objects from the specified type.
        /// </summary>
        /// <typeparam name="T">The type of the objects to be resolved.</typeparam>
        /// <returns>A <see cref="System.Array"/> object which contains all the objects resolved.</returns>
        protected virtual T[] DoGetServices<T>()
        {
            var services = this.DoGetServices(typeof(T));
            if (services == null || services.Length == 0)
                return new T[0];
            return services.Cast<T>().ToArray();
        }
        #endregion

        #region IObjectContainer Members
        /// <summary>
        /// 通过application/web配置文件初始化对象容器
        /// </summary>
        /// <param name="configSectionName">初始化对象容器结点名称.</param>
        public abstract void InitializeFromConfigFile(string configSectionName);
        /// <summary>
        /// 获得包括容器对象实例
        /// </summary>
        /// <typeparam name="T">包装容器类型.</typeparam>
        /// <returns>包装容器实例.</returns>
        public abstract T GetOriginalContainer<T>();
        /// <summary>
        /// 获得指定类型服务对象
        /// </summary>
        /// <typeparam name="T">服务对象类型.</typeparam>
        /// <returns>服务对象实例.</returns>
        public T GetService<T>()
        {
            var serviceImpl = this.DoGetService<T>();
            return (T)GetProxyObject(typeof(T), serviceImpl);
        }
        /// <summary>
        /// 获得 指定类型的服务对象
        /// </summary>
        /// <typeparam name="T">服务对象类型.</typeparam>
        /// <param name="overridedArguments">服务参数.</param>
        /// <returns>获得包括容器对象实例.</returns>
        public T GetService<T>(object overridedArguments)
        {
            var serviceImpl = this.DoGetService<T>(overridedArguments);
            return (T)GetProxyObject(typeof(T), serviceImpl);
        }
        /// <summary>
        /// 获得 指定类型的服务对象
        /// </summary>
        /// <param name="serviceType">服务对象类型.</param>
        /// <param name="overridedArguments">服务参数.</param>
        /// <returns>获得包括容器对象实例.</returns>
        public object GetService(Type serviceType, object overridedArguments)
        {
            object serviceImpl = this.DoGetService(serviceType, overridedArguments);
            return this.GetProxyObject(serviceType, serviceImpl);
        }
        /// <summary>
        /// 从指定类型分解对象.
        /// </summary>
        /// <param name="serviceType">对象类型.</param>
        /// <returns><see cref="System.Array"/>所有分解对象.</returns>
        public Array GetServices(Type serviceType)
        {
            var serviceImpls = this.DoGetServices(serviceType);
            if (serviceImpls == null)
                return new object[0];

            var proxiedServiceImpls = new List<object>();
            foreach (var serviceImpl in serviceImpls)
                proxiedServiceImpls.Add(GetProxyObject(serviceType, serviceImpl));
            return proxiedServiceImpls.ToArray();
        }
        /// <summary>
        /// 分解指定在的类型对象
        /// </summary>
        /// <typeparam name="T">分解对象的类型.</typeparam>
        /// <returns><see cref="System.Array"/>所有分解对象.</returns>
        public T[] GetServices<T>()
        {
            var serviceImpls = this.DoGetServices<T>();
            if (serviceImpls == null)
                return new List<T>().ToArray();

            var proxiedServiceImpls = new List<T>();
            foreach (var serviceImpl in serviceImpls)
                proxiedServiceImpls.Add((T)GetProxyObject(typeof(T), serviceImpl));
            return proxiedServiceImpls.ToArray();
        }
        #endregion

        #region IServiceProvider Members
        /// <summary>
        /// 指定类型的服务对象
        /// </summary>
        /// <param name="serviceType">指定类型的服务对象.</param>
        /// <returns>指定类型的服务对象.</returns>
        public object GetService(Type serviceType)
        {
            object serviceImpl = this.DoGetService(serviceType);
            return GetProxyObject(serviceType, serviceImpl);
        }

        #endregion

        #region IServiceRegistrar Members
        /// <summary>
        /// 根据指定的源类型(父类)、目标类(具体实现类)型进行IOC注册
        /// </summary>
        /// <typeparam name="TFrom">源类型(父类)</typeparam>
        /// <typeparam name="TTo">目标类(具体实现类)</typeparam>
        /// <returns>已注册对象实例</returns>
        public IServiceRegistrar RegisterServiceType<TFrom, TTo>()
        {
            return RegisterServiceType(typeof(TFrom), typeof(TTo));
        }
        /// <summary>
        ///  根据指定的源类型(父类)、目标类(具体实现类)和指定的类名称型进行IOC注册
        /// </summary>
        /// <typeparam name="TFrom">源类型(父类)</typeparam>
        /// <typeparam name="TTo">目标类(具体实现类)</typeparam>
        /// <param name="name">指定的类名称</param>
        /// <returns>已注册对象实例</returns>
        public IServiceRegistrar RegisterServiceType<TFrom, TTo>(string name)
        {
            return RegisterServiceType(typeof(TFrom), typeof(TTo), name);
        }
        /// <summary>
        ///  根据指定的源类型(父类)、目标类(具体实现类)和指定的生命周期进行IOC注册
        /// </summary>
        /// <typeparam name="TFrom">源类型(父类)</typeparam>
        /// <typeparam name="TTo">目标类(具体实现类)</typeparam>
        /// <param name="lifetimeStyle">指定的生命周期</param>
        /// <returns>已注册对象实例</returns>
        public IServiceRegistrar RegisterServiceType<TFrom, TTo>(LifetimeStyle lifetimeStyle)
        {
            return RegisterServiceType(typeof(TFrom), typeof(TTo), lifetimeStyle);
        }
        /// <summary>
        ///  根据指定的源类型(父类)、目标类(具体实现类)和指定的类名称和生命周期进行IOC注册
        /// </summary>
        /// <typeparam name="TFrom">源类型(父类)</typeparam>
        /// <typeparam name="TTo">目标类(具体实现类)</typeparam>
        /// <param name="name">指定的类名称</param>
        /// <param name="lifetimeStyle">指定的生命周期</param>
        /// <returns>已注册对象实例</returns>
        public IServiceRegistrar RegisterServiceType<TFrom, TTo>(string name, LifetimeStyle lifetimeStyle)
        {
            return RegisterServiceType(typeof(TFrom), typeof(TTo), name, lifetimeStyle);
        }
        /// <summary>
        /// 根据指定的源类型(父类)、目标类(具体实现类)型进行IOC注册
        /// </summary>
        /// <param name="from">源类型(父类)</param>
        /// <param name="to">目标类(具体实现类)</param>
        /// <returns>已注册对象实例</returns>
        public IServiceRegistrar RegisterServiceType(Type from, Type to)
        {
            return RegisterServiceType(from, to, LifetimeStyle.Transient);
        }
        /// <summary>
        ///  根据指定的源类型(父类)、目标类(具体实现类)和指定的类名称型进行IOC注册
        /// </summary>
        /// <param name="from">源类型(父类)</param>
        /// <param name="to">目标类(具体实现类)</param>
        /// <param name="name">指定的类名称</param>
        /// <returns>已注册对象实例</returns>
        public IServiceRegistrar RegisterServiceType(Type from, Type to, string name)
        {
            return RegisterServiceType(from, to, name, LifetimeStyle.Transient);
        }
        /// <summary>
        /// Registers the instance as singleton.
        /// </summary>
        /// <typeparam name="TService">Type of the service.</typeparam>
        /// <param name="instance">The instance.</param>
        /// <returns></returns>
        public IServiceRegistrar RegisterInstance<TService>(object instance)
        {
            return RegisterInstance(typeof(TService), instance);
        }
        /// <summary>
        ///  根据指定的源类型(父类)、目标类(具体实现类)和指定的生命周期进行IOC注册
        /// </summary>
        /// <param name="from">源类型(父类)</param>
        /// <param name="to">目标类(具体实现类)</param>
        /// <param name="lifetimeStyle">指定的生命周期</param>
        /// <returns>已注册对象实例</returns>
        public abstract IServiceRegistrar RegisterServiceType(Type from, Type to, LifetimeStyle lifetimeStyle);
        /// <summary>
        ///  根据指定的源类型(父类)、目标类(具体实现类)和指定的类名称和生命周期进行IOC注册
        /// </summary>
        /// <param name="from">源类型(父类)</param>
        /// <param name="to">目标类(具体实现类)</param>
        /// <param name="name">指定的类名称</param>
        /// <param name="lifetimeStyle">指定的生命周期</param>
        /// <returns>已注册对象实例</returns>
        public abstract IServiceRegistrar RegisterServiceType(Type from, Type to, string name, LifetimeStyle lifetimeStyle);
        /// <summary>
        /// Registers the instance as singleton.
        /// </summary>
        /// <param name="serviceType">Type of the service.</param>
        /// <param name="instance">The instance.</param>
        /// <returns></returns>
        public abstract IServiceRegistrar RegisterInstance(Type serviceType, object instance);

        #endregion

        #region IServiceLocator Members
        /// <summary>
        /// 返回一个 <see cref="Boolean"/> 值判断服务加载器是否注册.
        /// </summary>
        /// <typeparam name="T">判断类型.</typeparam>
        /// <returns>True 类型已注册, 否则, false.</returns>.
        public abstract bool Registered<T>();
        /// <summary>
        /// 返回一个 <see cref="Boolean"/> 值判断服务加载器是否注册.
        /// </summary>
        /// <param name="type">判断类型.</param>
        /// <returns>True 类型已注册, 否则, false.</returns>
        public abstract bool Registered(Type type);

        #endregion

        #region IServiceInjector Members
        /// <summary>
        /// Injects the matching dependences.
        /// </summary>
        /// <param name="instance">The instance.</param>
        public abstract void Inject(object instance);
        #endregion
    }
}